package org.example.seckillsample.serviceImpl;

import org.example.seckillsample.entity.Commodity;
import org.example.seckillsample.mapper.CommodityMapper;
import org.example.seckillsample.service.SecKillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

@Service
public class SecKillServiceImpl implements SecKillService {
   private final CommodityMapper commodityMapper;
   private final StringRedisTemplate stringRedisTemplate;
   private final DefaultRedisScript<Boolean> redisScript;

   public SecKillServiceImpl(CommodityMapper commodityMapper, StringRedisTemplate stringRedisTemplate){
       this.commodityMapper = commodityMapper;
       this.stringRedisTemplate = stringRedisTemplate;
       this.redisScript = new DefaultRedisScript<>();
       redisScript.setResultType(Boolean.class);
       String script = "if tonumber(redis.call('HGET',KEYS[1],'stock'))<=0 then return false;"
               +"else redis.call('HINCRBY',KEYS[1],'stock',-1); return true;"
               +"end;";
       redisScript.setScriptText(script);
   }
    @Override
    public List<Commodity> findAll() {
        BoundSetOperations<String,String> boundSetOperations =stringRedisTemplate.boundSetOps("commodity");
        HashOperations<String,String,String> hashOperations = stringRedisTemplate.opsForHash();
        Set<String> commoditySet = boundSetOperations.members();
        List<Commodity> commodityList;
        if(commoditySet==null||commoditySet.isEmpty()){
            commodityList = commodityMapper.findAll();
            for(Commodity commodity:commodityList){
                String id = String.valueOf(commodity.getId());
                boundSetOperations.add(id);
                hashOperations.putIfAbsent("commodity:"+id,"title",commodity.getTitle());
                hashOperations.putIfAbsent("commodity:"+id,"price",commodity.getPrice().toString());
                hashOperations.putIfAbsent("commodity:"+id,"stock",String.valueOf(commodity.getStock()));
            }
        }else{
            commodityList = new ArrayList<>();
            Commodity commodity;
            for(String id:commoditySet){
                String title = hashOperations.get("commodity:"+id,"title");
                String price = hashOperations.get("commodity:"+id,"price");
                String stock = hashOperations.get("commodity:"+id,"stock");
                if(title==null||price==null||stock==null){
                    commodity = commodityMapper.findById(Long.parseLong(id));
                    if(commodity!=null){
                        hashOperations.putIfAbsent("commodity:"+id,"title",commodity.getTitle());
                        hashOperations.putIfAbsent("commodity:"+id,"price",commodity.getPrice().toString());
                        hashOperations.putIfAbsent("commodity:"+id,"stock",String.valueOf(commodity.getStock()));
                    }
                }else{
                    commodity = new Commodity(Long.parseLong(id),title,new BigDecimal(price),Integer.parseInt(stock));
                }
                commodityList.add(commodity);
            }

        }
        return commodityList;
    }

    @Override
    public Commodity findById(Long commodityId) {
        Commodity commodity;
        BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate
                .boundHashOps("commodity:"+commodityId);
        String title = boundHashOperations.get("title");
        String price = boundHashOperations.get("price");
        String stock = boundHashOperations.get("stock");
        if(title==null||price==null||stock==null){
            commodity = commodityMapper.findById(commodityId);
            boundHashOperations.putIfAbsent("title",commodity.getTitle());
            boundHashOperations.putIfAbsent("price",commodity.getPrice().toString());
            boundHashOperations.putIfAbsent("stock",String.valueOf(commodity.getStock()));
        }else{
            commodity = new Commodity(commodityId,title,new BigDecimal(price),Integer.parseInt(stock));
        }
        return commodity;
    }

    @Override
    public boolean buy(long commodityId, String money, String phone) {
       money  = "1";
       phone = "1";
        BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate
                .boundHashOps("commodity:"+commodityId);
        String stockString = boundHashOperations.get("stock");
        long stock;
        if(stockString==null){
            Commodity commodity = commodityMapper.findById(commodityId);
            stock = commodity.getStock();
            boundHashOperations.putIfAbsent("title",commodity.getTitle());
            boundHashOperations.putIfAbsent("price",commodity.getPrice().toString());
            boundHashOperations.putIfAbsent("stock",String.valueOf(stock));
        }else{
            stock = Long.parseLong(stockString);
        }
        if(stock<0){
            return false;
        }else{
            Boolean result = stringRedisTemplate.execute(redisScript, Collections.singletonList("commodity:"+commodityId));
            if(result==null||!result){
                return false;
            }
        }
        stringRedisTemplate.convertAndSend("mq","{"
        + "\"commodityId\":"+commodityId
        + ",\"money\":"+money
        + ",\"phone\":\""+phone+"\""
        + "}");
        return true;
    }
}
